package de.sabram.upb.specs.validation;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.validation.Check;

import de.sabram.upb.specs.ptg.Argument;
import de.sabram.upb.specs.ptg.Item;
import de.sabram.upb.specs.ptg.Insertion;
import de.sabram.upb.specs.ptg.Optional;
import de.sabram.upb.specs.ptg.PatternBody;
import de.sabram.upb.specs.ptg.PtgPackage;

public class PtgJavaValidator extends AbstractPtgJavaValidator {
	class Tuple {
		public int index;
		public String type;

		public Tuple(int index2, String name) {
			this.index = index2;
			this.type = name;
		}

	}

	@Check
	public void checkMixingOfIndexedAndNonIndexedInsertionPoints(
			PatternBody body) {
		List<EObject> body_list = body.getPatternBody();
		ArrayList<Boolean> indexSets = new ArrayList<Boolean>();
		for (EObject object : body_list) {
			if (object instanceof Item) {
				Item i = ((Item) object);
				if (i.getInsertion() != null) {
					// index set
					if (i.getInsertion().getIndex() != 0)
						indexSets.add(true);
					else
						indexSets.add(false);
				}
				if (i.getItemCall() != null) {
					for (Argument arg : i.getItemCall().getArguments()) {
						if (arg.getInsertion().getIndex() != 0)
							indexSets.add(true);
						else
							indexSets.add(false);
					}
				}
			}
			if (object instanceof Optional) {
				List<Item> items = ((Optional) object).getItems();
				for (Item item : items) {
					Item i = ((Item) item);
					if (i.getInsertion() != null) {
						if (i.getInsertion().getIndex() != 0)
							indexSets.add(true);
						else
							indexSets.add(false);
					}
					if (i.getItemCall() != null) {
						for (Argument arg : i.getItemCall().getArguments()) {
							if (arg.getInsertion().getIndex() != 0)
								indexSets.add(true);
							else
								indexSets.add(false);
						}
					}
				}
			}
		}
		boolean initial = false;
		if (indexSets != null && !indexSets.isEmpty()) {
			initial = indexSets.get(0).booleanValue();
			for (Iterator<Boolean> iter = indexSets.iterator(); iter.hasNext();) {
				if (iter.next().booleanValue() != initial) {
					error("A Pattern must not contain a mix of indexed and non-indexed insertion points",
							PtgPackage.Literals.PATTERN_BODY__PATTERN_BODY);
					break;
				}
			}
		}
	}

	@Check
	public void checkDifferentType(PatternBody body) {
		List<EObject> body_list = body.getPatternBody();
		ArrayList<Tuple> indexSets = new ArrayList<Tuple>();
		for (EObject object : body_list) {
			if (object instanceof Item) {
				Item i = ((Item) object);
				if (i.getInsertion() != null) {
					// index set
					if (i.getInsertion().getIndex() != 0)
						indexSets.add(new Tuple(i.getInsertion().getIndex(), i
								.getInsertion().getType().getName()));
				}
				if (i.getItemCall() != null) {
					for (Argument arg : i.getItemCall().getArguments()) {
						if (arg.getInsertion().getIndex() != 0)
							indexSets.add(new Tuple(arg.getInsertion()
									.getIndex(), arg.getInsertion().getType()
									.getName()));
					}
				}
			}
			if (object instanceof Optional) {
				List<Item> items = ((Optional) object).getItems();
				for (Item item : items) {
					Item i = ((Item) item);
					if (i.getInsertion() != null) {
						if (i.getInsertion().getIndex() != 0)
							indexSets
									.add(new Tuple(i.getInsertion().getIndex(),
											i.getInsertion().getType()
													.getName()));
					}
					if (i.getItemCall() != null) {
						for (Argument arg : i.getItemCall().getArguments()) {
							if (arg.getInsertion().getIndex() != 0)
								indexSets.add(new Tuple(arg.getInsertion()
										.getIndex(), arg.getInsertion()
										.getType().getName()));
						}
					}
				}
			}
		}
		if (indexSets != null && !indexSets.isEmpty()) {
			HashMap<Integer, String> result = new HashMap<Integer, String>();
			for (Iterator<Tuple> iter = indexSets.iterator(); iter.hasNext();) {
				Tuple t = iter.next();
				if (result.containsKey(t.index)
						&& result.get(t.index) != t.type) {
					error("A Pattern must not contain different types for indexed insertions",
							PtgPackage.Literals.PATTERN_BODY__PATTERN_BODY);
					break;

				} else {
					result.put(t.index, t.type);
				}
			}
		}
	}
}